# -*- coding: UTF-8 -*-

import gtk

#
# General note: justify all labels in tables left due to Issue 3
#
# http://code.google.com/p/habr-monitor-applet/issues/detail?id=3
#

class SettingsWindow:
    __PADDING = 3
    __ALIGNMENT_PADDING = 3 * __PADDING

    __Dialog = None

    # Interface methods

    def __init__(self, gconf, nm_observee):
        if self.__Dialog is not None:
            #
            # There is already a settings window displayed.
            # Bring it to the front (and to the current workspace
            # if necessary).
            #
            if self.__Dialog.dialog is not None:
                self.__Dialog.dialog.present()
                return
        else:
            #
            # Look at several lines above to understand
            # why we need to initiailize self.dialog here.
            #
            self.dialog = None
            SettingsWindow.__Dialog = self

            #
            # These widgets will be places on "Common" tab
            #
        self.nick = gtk.Entry()
        self.refreshInterval = gtk.SpinButton()
        self.refreshInterval.set_range(1, 100)
        self.refreshInterval.set_increments(1, 10)

        self.nmStatus = gtk.Label()
        self.nmStatus.set_alignment(0, 0.5)

        self.nmError = gtk.TextView()
        self.nmError.set_editable(False)
        self.nmError.set_wrap_mode(gtk.WRAP_WORD_CHAR)
        self.nmError.set_no_show_all(True)

        self.proxyStatus = gtk.Label()
        self.proxyStatus.set_text(
            _('Proxy is not used') if gconf.http_proxy is None else \
            _('Proxy currently used: %s') % gconf.http_proxy)
        self.proxyStatus.set_alignment(0, 0.5)
        self.proxyStatus.set_selectable(True)
            #
            # "Appearance" tab
            #
        self.textIsAlwaysHorizontal = gtk.CheckButton(_('Lay out text horizontally\nwhen placed in a vertical panel'))
        self.layoutInRow = gtk.RadioButton(None, _('In row'))
        self.layoutStacked = gtk.RadioButton(self.layoutInRow, _('Stacked'))

        self.karmaFontIsDefault = gtk.RadioButton(None, _('Default'))
        self.karmaFontIsCustom = gtk.RadioButton(self.karmaFontIsDefault, _('Custom'))
        self.karmaFont = gtk.FontButton()
        self.karmaTextColor = gtk.ColorButton()
        self.habrapowerTextColor = gtk.ColorButton()

        self.showRating = gtk.CheckButton(_('Show rank'))
        self.ratingFontIsDefault = gtk.RadioButton(None, _('Default'))
        self.ratingFontIsCustom = gtk.RadioButton(self.ratingFontIsDefault, _('Custom'))
        self.ratingFont = gtk.FontButton()
        self.ratingTextColor = gtk.ColorButton()

        if nm_observee.enabled:
            self.nmStatus.set_text(_('Integration is enabled.'))
            self.nmError.hide()
        else:
            self.nmStatus.set_text(_('Integration is disabled. Reason:'))
            self.nmError.show()
            self.nmError.get_buffer().set_text(nm_observee.error)

        self.__read_settings(gconf)
        self.__connect_signals(gconf)

        # Fill the dialog

        commonVbox = self.__fillCommonTab()
        appearanceVbox = self.__fillAppearanceTab()

        notebook = gtk.Notebook()
        notebook.set_border_width(6)
        notebook.append_page(commonVbox, gtk.Label(_('Common')))
        notebook.append_page(appearanceVbox, gtk.Label(_('Appearance')))
        notebook.show_all()

        self.dialog = gtk.Dialog(_("Preferences"), None,
            gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
            (gtk.STOCK_CLOSE, gtk.RESPONSE_ACCEPT))

            #
            # Use 6 in order to align the right borders of the notebook
            # and the right border of the Ok button. I think,
            # 6 could be the value we can read from 'action-area-border'
            # or 'button-spacing' property but dialog.get_property(..)
            # for those somehow fails...
            #
        self.dialog.vbox.pack_start(notebook, True, True, 0)

        self.dialog.set_icon_from_file('/usr/share/gnome-panel/pixmaps/habr-monitor-applet.png')
        self.dialog.set_property('has-separator', False)
        self.dialog.set_resizable(False)

        # Run the dialog

        self.dialog.run()
        self.dialog.destroy()

        SettingsWindow.__Dialog = None

    # Helper GUI methods

    def __fillCommonTab(self):

        hbox1 = gtk.HBox()
        hbox1.pack_start(gtk.Label(_('Nick:')), False, False, 0)
        hbox1.pack_start(self.nick, True, True, self.__PADDING)

        hbox2 = gtk.HBox()
        hbox2.pack_start(gtk.Label(_('Refresh interval:')), False, False, 0)
        hbox2.pack_start(self.refreshInterval, True, True, self.__PADDING)
        hbox2.pack_start(gtk.Label(_('min.')), False, False, self.__PADDING)

        vbox = gtk.VBox()
        vbox.pack_start(hbox1, False, False, self.__PADDING)
        vbox.pack_start(hbox2, False, False, self.__PADDING)

        alignment = gtk.Alignment(xalign=0, yalign=0, xscale=1, yscale=1)
        alignment.set_padding(
            padding_top=0,
            padding_bottom=0,
            padding_left=self.__ALIGNMENT_PADDING,
            padding_right=0)
        alignment.add(vbox)


        nmLabel = gtk.Label()
        nmLabel.set_markup(_('<b>NetworkManager integration</b>'))
        nmLabel.set_alignment(0, 0.5)
        nmLabel.set_padding(self.__PADDING, self.__PADDING)

        nmAbout = gtk.Label()
        nmAbout.set_markup(_('<i>NetworkManager integration enables the applet to detect when the network is unreachable and trying to connect to Habrahabr is useless.</i>'''))
        nmAbout.set_alignment(0, 0.5)
        nmAbout.set_line_wrap(True)

        nmVbox = gtk.VBox()
        nmVbox.pack_start(nmAbout, False, False, self.__PADDING)
        nmVbox.pack_start(self.nmStatus, False, False, self.__PADDING)
        nmVbox.pack_start(self.nmError, False, False, self.__PADDING)

        nmAlignment = gtk.Alignment(xalign=0, yalign=0, xscale=1, yscale=1)
        nmAlignment.set_padding(
            padding_top=0,
            padding_bottom=0,
            padding_left=self.__ALIGNMENT_PADDING,
            padding_right=0)
        nmAlignment.add(nmVbox)


        proxyLabel = gtk.Label()
        proxyLabel.set_markup(_('<b>Proxy</b>'))
        proxyLabel.set_alignment(0, 0.5)
        proxyLabel.set_padding(self.__PADDING, self.__PADDING)

        proxyAbout = gtk.Label()
        proxyAbout.set_markup(_('<i>The applet supports HTTP proxies, even those requiring authentication. To discover a proxy the applet uses <tt>http_proxy</tt> environment variable if it is defined and GNOME proxy settings otherwise.</i>'''))
        proxyAbout.set_alignment(0, 0.5)
        proxyAbout.set_line_wrap(True)

        proxyAboutRefresh = gtk.Label()
        proxyAboutRefresh.set_markup(_('<i>After you change your system proxy settings, restart the applet to apply them.</i>'))
        proxyAboutRefresh.set_alignment(0, 0.5)
        proxyAboutRefresh.set_line_wrap(True)

        proxyVbox = gtk.VBox()
        proxyVbox.pack_start(proxyAbout, False, False, self.__PADDING)
        proxyVbox.pack_start(proxyAboutRefresh, False, False, self.__PADDING)
        proxyVbox.pack_start(self.proxyStatus, False, False, self.__PADDING)

        proxyAlignment = gtk.Alignment(xalign=0, yalign=0, xscale=1, yscale=1)
        proxyAlignment.set_padding(
            padding_top=0,
            padding_bottom=0,
            padding_left=self.__ALIGNMENT_PADDING,
            padding_right=0)
        proxyAlignment.add(proxyVbox)


        commonVbox = gtk.VBox()
        commonVbox.pack_start(alignment, False, False, 0)
        commonVbox.pack_start(nmLabel, False, False, self.__PADDING)
        commonVbox.pack_start(nmAlignment, False, False, 0)
        commonVbox.pack_start(proxyLabel, False, False, self.__PADDING)
        commonVbox.pack_start(proxyAlignment, False, False, 0)
        commonVbox.set_border_width(self.__PADDING)

            #
            # From <http://library.gnome.org/devel/gtk/unstable/GtkLabel.html#gtk-label-set-line-wrap>
            #
            # Setting line wrapping to TRUE does not make the label wrap at its
            # parent container's width, because GTK+ widgets conceptually can't
            # make their requisition depend on the parent container's size.
            # For a label that wraps at a specific position, set the label's
            # width using gtk_widget_set_size_request().
            #
        def resize_labels(_, allocation):
            w = allocation.width
            nmAbout.set_size_request(width=w, height=-1)
            proxyAbout.set_size_request(width=w, height=-1)
            proxyAboutRefresh.set_size_request(width=w, height=-1)
        nmVbox.connect('size-allocate', resize_labels)

        return commonVbox

    def __fillAppearanceTab(self):

        textArrangementLabel = gtk.Label(_('Text arrangement:'))
        textArrangementLabel.set_alignment(0, 0.5)
        textArrangementLabel.set_padding(self.__PADDING, self.__PADDING)

        textArrangementVbox = gtk.VBox()
        textArrangementVbox.pack_start(self.layoutInRow, False, False, self.__PADDING)
        textArrangementVbox.pack_start(self.layoutStacked, False, False, self.__PADDING)

        textArrangementAlignment = gtk.Alignment(xalign=0, yalign=0, xscale=1, yscale=1)
        textArrangementAlignment.set_padding(
            padding_top=0,
            padding_bottom=0,
            padding_left=self.__ALIGNMENT_PADDING,
            padding_right=0)
        textArrangementAlignment.add(textArrangementVbox)

        commonVbox = gtk.VBox()
        commonVbox.pack_start(self.textIsAlwaysHorizontal, True, False, self.__PADDING)
        commonVbox.pack_start(textArrangementLabel, False, False, self.__PADDING)
        commonVbox.pack_start(textArrangementAlignment, False, False, 0)

        commonExpander = gtk.Expander(_('<b>Common</b>'))
        commonExpander.set_use_markup(True)
        commonExpander.add(commonVbox)


        karmaTable = gtk.Table(2, 2, homogeneous=False)
        #
        l = gtk.Label(_('Karma text color:'))
        l.set_alignment(0, 0.5)
        karmaTable.attach(l, 0, 1, 0, 1,
            gtk.FILL, 0, self.__PADDING, self.__PADDING)
        #
        karmaTable.attach(self.karmaTextColor, 1, 2, 0, 1,
            gtk.EXPAND | gtk.FILL, 0, self.__PADDING, self.__PADDING)
        #
        l = gtk.Label(_('Habrapower text color:'))
        l.set_alignment(0, 0.5)
        karmaTable.attach(l, 0, 1, 1, 2,
            gtk.FILL, 0, self.__PADDING, self.__PADDING)
        #
        karmaTable.attach(self.habrapowerTextColor, 1, 2, 1, 2,
            gtk.EXPAND | gtk.FILL, 0, self.__PADDING, self.__PADDING)

        karmaVbox = gtk.VBox()
        self.__vbox_pack_start_font_selection(karmaVbox,
            self.karmaFontIsDefault,
            self.karmaFontIsCustom,
            self.karmaFont)
        karmaVbox.pack_start(karmaTable, False, False, self.__PADDING)

        karmaExpander = gtk.Expander(_('<b>Karma and habrapower</b>'))
        karmaExpander.set_use_markup(True)
        karmaExpander.add(karmaVbox)


        ratingVbox = gtk.VBox()
        ratingVbox.pack_start(self.showRating, False, False, self.__PADDING)
        ratingFontAlignment = self.__vbox_pack_start_font_selection(ratingVbox,
            self.ratingFontIsDefault,
            self.ratingFontIsCustom,
            self.ratingFont)

        hbox = gtk.HBox()
        hbox.pack_start(gtk.Label(_('Text color:')), False, False, self.__PADDING)
        hbox.pack_start(self.ratingTextColor, True, True, self.__PADDING)
        ratingVbox.pack_start(hbox, False, False, self.__PADDING)

        ratingExpander = gtk.Expander(_('<b>Rank</b>'))
        ratingExpander.set_use_markup(True)
        ratingExpander.add(ratingVbox)

        def toggle(toggleButton):
            active = toggleButton.get_active()
            ratingFontAlignment.set_sensitive(active)
            self.ratingTextColor.set_sensitive(active)
        toggle(self.showRating)
        self.showRating.connect('toggled', toggle)


        appearanceVbox = gtk.VBox()
        appearanceVbox.pack_start(commonExpander, False, False, self.__PADDING)
        appearanceVbox.pack_start(karmaExpander, False, False, self.__PADDING)
        appearanceVbox.pack_start(ratingExpander, False, False, self.__PADDING)
        appearanceVbox.set_border_width(self.__PADDING)

        return appearanceVbox

    # Helper settings methods

    def __connect_signals(self, gconf):

        def signal_nick(entry, user_data):
            gconf.nick.set(entry.get_chars(0, -1))
            return False # propagate the event further
        def signal_refreshInterval(spinButton, user_data):
            gconf.refreshInterval.set(spinButton.get_value_as_int())
            return False # propagate the event further

        self.nick.connect('focus-out-event', signal_nick)
        self.refreshInterval.connect('focus-out-event', signal_refreshInterval)

        def signal_layoutInRow(toggleButton):
            gconf.layoutInRow.set(toggleButton.get_active())
        def signal_textIsAlwaysHorizontal(toggleButton):
            gconf.textIsAlwaysHorizontal.set(toggleButton.get_active())
        def signal_showRating(toggleButton):
            gconf.showRating.set(toggleButton.get_active())

        self.layoutInRow.connect('toggled', signal_layoutInRow)
        self.textIsAlwaysHorizontal.connect('toggled', signal_textIsAlwaysHorizontal)
        self.showRating.connect('toggled', signal_showRating)

        def signal_karmaTextColor(colorButton):
            gconf.karmaTextColor.set(colorButton.get_color())
        def signal_habrapowerTextColor(colorButton):
            gconf.habrapowerTextColor.set(colorButton.get_color())
        def signal_ratingTextColor(colorButton):
            gconf.ratingTextColor.set(colorButton.get_color())

        self.karmaTextColor.connect('color-set', signal_karmaTextColor)
        self.habrapowerTextColor.connect('color-set', signal_habrapowerTextColor)
        self.ratingTextColor.connect('color-set', signal_ratingTextColor)

        def signal_karmaFont(fontButton):
            gconf.karmaFont.set_font_name(fontButton.get_font_name())
        def signal_ratingFont(fontButton):
            gconf.ratingFont.set_font_name(fontButton.get_font_name())

        self.karmaFont.connect('font-set', signal_karmaFont)
        self.ratingFont.connect('font-set', signal_ratingFont)

        def signal_karmaFontIsCustom(toggleButton):
            active = toggleButton.get_active()
            gconf.karmaFont.set_custom(active)
            if active:
                # See the comment below in signal_ratingFontIsCustom()
                signal_karmaFont(self.karmaFont)
        def signal_ratingFontIsCustom(toggleButton):
            active = toggleButton.get_active()
            gconf.ratingFont.set_custom(active)
            if active:
                #
                # Manually call that handler to save the currently
                # chosen font. This will be useful in the following
                # situation:
                #
                # * The user runs the applet first time
                # * Open the settings window
                # * Choose "Rating" tab
                # * Change font to "Custom"
                # * Is happy with font selected as custom by default
                #   (see GConfClient.__DEFAULTS)
                # * Close the settings window
                # * After some time reboot the machine
                # * And see that applet has default font again
                #
                # Applet will set font to default again as the
                # custom one is not still in the GConf database!
                #
                signal_ratingFont(self.ratingFont)

        self.karmaFontIsCustom.connect('toggled', signal_karmaFontIsCustom)
        self.ratingFontIsCustom.connect('toggled', signal_ratingFontIsCustom)

    def __read_settings(self, gconf):

        self.nick.set_text(gconf.nick .value())
        self.refreshInterval.set_value(gconf.refreshInterval.value())

        (self.layoutInRow if gconf.layoutInRow.value() else self.layoutStacked).set_active(True)
        self.textIsAlwaysHorizontal.set_active(gconf.textIsAlwaysHorizontal.value())
        self.showRating.set_active(gconf.showRating.value())

        self.karmaTextColor.set_color(gconf.karmaTextColor.value())
        self.habrapowerTextColor.set_color(gconf.habrapowerTextColor.value())
        self.ratingTextColor.set_color(gconf.ratingTextColor.value())

        self.karmaFont.set_font_name(gconf.karmaFont.font_name())
        self.ratingFont.set_font_name(gconf.ratingFont.font_name())

        (self.karmaFontIsCustom if gconf.karmaFont.is_custom() else self.karmaFontIsDefault).set_active(True)
        (self.ratingFontIsCustom if gconf.ratingFont.is_custom() else self.ratingFontIsDefault).set_active(True)


    # Utility GUI methods

        #
        # `Self` is needed here for `self.__PADDING` only
        #
    def __vbox_pack_start_font_selection(self, vbox,
        radioButton_isDefault,
        radioButton_isCustom,
        fontButton):
        '''
        Put some widgets to the specified VBox as follows:

        vbox
        |                                         |
        | Font:                                   |
        | + - - - - - - - - - - - - - - - - - - +---GtkAlignment
        | | [radioButton_isDefault]             | |
        | | [radioButton_isCustom] [fontButton] | |
        | + - - - - - - - - - - - - - - - - - - + |
        |                                         |

        Function will connect some signals to disable the font
        button when "Default" is selected.

        Returns the GtkAlignment object. It can be used to disable
        all widgets in it with one method call
        alignment.set_sensitive(False).
        '''

        # "Font" label

        l = gtk.Label(_('Font:'))
        l.set_alignment(0, 0.5)
        l.set_padding(self.__PADDING, self.__PADDING)

        vbox.pack_start(l, False, False, self.__PADDING)

        # Radio buttons

        hbox2 = gtk.HBox()
        hbox2.pack_start(radioButton_isCustom, False, False, 0)
        hbox2.pack_start(fontButton, True, True, self.__PADDING)

        vbox2 = gtk.VBox()
        vbox2.pack_start(radioButton_isDefault, False, False, self.__PADDING)
        vbox2.pack_start(hbox2, False, False, self.__PADDING)

        alignment = gtk.Alignment(xalign=0, yalign=0, xscale=1, yscale=1)
        alignment.set_padding(
            padding_top=0,
            padding_bottom=0,
            padding_left=self.__ALIGNMENT_PADDING,
            padding_right=0)
        alignment.add(vbox2)

            #
            # Alignment does already have vertical padding
            #
        vbox.pack_start(alignment, False, False, 0)

        # Connect signals

        def toggle(radioButton):
            fontButton.set_sensitive( radioButton.get_active() )

        toggle(radioButton_isCustom)
        radioButton_isCustom.connect('toggled', toggle)

        # Finish

        return alignment
